﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="ClusterMethodActioner.cs" company="DissingNelleman">
//   
// All rights reserved. </copyright>
// <summary>
//   The cluster method actioner.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace ServiceLibrary.Actioners.Activities
{
    using System;
    using System.Collections.Generic;
    using System.Linq;

    using NHibernate;

    using ServiceLibrary.Models.Base;
    using ServiceLibrary.Models.Domain;
    using ServiceLibrary.Services.Commands;
    using ServiceLibrary.Services.Queries;
    using ServiceLibrary.Services.Results;
    using ServiceLibrary.Actioners.Base;

    /// <summary>
    /// The cluster method actioner.
    /// </summary>
    public class ClusterMethodActioner : ActionerBase
    {
        #region Constructors and Destructors

        /// <summary>
        /// Initializes a new instance of the <see cref="ClusterMethodActioner"/> class.
        /// </summary>
        /// <param name="session">
        /// The session.
        /// </param>
        /// <param name="activeUser">
        /// The active user.
        /// </param>
        public ClusterMethodActioner(ISession session, User activeUser)
            : base(session, activeUser)
        {
        }

        #endregion

        #region Public Methods and Operators

        /// <summary>
        /// The create cluster method.
        /// </summary>
        /// <param name="method">
        /// The method.
        /// </param>
        /// <returns>
        /// The <see cref="Guid"/>.
        /// </returns>
        public Guid CreateClusterMethod(ClusterMethod method)
        {
            method.CreatedDateTime = DateTime.Now;
            this.Session.Save(method);

            return method.ID;
        }

        /// <summary>
        /// The create cluster method.
        /// </summary>
        /// <param name="cmd">
        /// The cmd.
        /// </param>
        public void CreateClusterMethod(CreateClusterMethodCommand cmd)
        {
            if (cmd.Method != null)
            {
                var method = new ClusterMethod
                                 {
                                     ID = cmd.Method.ID, 
                                     Comments = cmd.Method.Comments, 
                                     ArchiveLocation = cmd.Method.ArchiveLocation, 
                                     Type = this.Session.Get<ClusterMethodType>(cmd.Method.Type)
                                 };

                if (cmd.Method.Files != null && cmd.Method.Files.Any())
                {
                    IEnumerable<Guid> fileIDs = cmd.Method.Files;

                    foreach (Guid id in fileIDs)
                    {
                        var newAddition = this.Session.Get<File>(id);
                        if (newAddition != null && !method.Files.Contains(newAddition))
                        {
                            method.Files.Add(newAddition);
                        }
                    }
                }

                CreateClusterMethod(method);
            }
        }

        /// <summary>
        /// The create cluster method type.
        /// </summary>
        /// <param name="name">
        /// The name.
        /// </param>
        public void CreateClusterMethodType(string name)
        {
            var type = new ClusterMethodType
                           {
                               ID = Guid.NewGuid(), 
                               Name = name
                           };
            this.Session.Save(type);
        }

        /// <summary>
        /// The execute search query.
        /// </summary>
        /// <param name="clusterMethodQuery">
        /// The cluster method query.
        /// </param>
        /// <returns>
        /// The <see cref="ClusterMethodResult"/>.
        /// </returns>
        public ClusterMethodResult ExecuteSearchQuery(ClusterMethodQuery clusterMethodQuery)
        {
            SearchSettings settings = clusterMethodQuery.Settings;
            var result = new ClusterMethodResult();

            IQueryOver<ClusterMethod, ClusterMethod> search = this.Session.QueryOver<ClusterMethod>();
            this.ApplyDefaultCriterias(clusterMethodQuery.Settings, search);

            result.TotalRowCount = search.RowCount();
            IList<ClusterMethod> list = ApplySkipAndTake(settings, search);

            if (list.Any())
            {
                list = list.OrderByDescending(x => x.CreatedDateTime).ToList();
                foreach (ClusterMethod method in list)
                {
                    result.List.Add(Services.Dto.ClusterMethod.Convert(method));
                }
            }

            return result;
        }

        /// <summary>
        /// The query all cluster method types.
        /// </summary>
        /// <param name="clusterMethodTypeQuery">
        /// The cluster method type query.
        /// </param>
        /// <returns>
        /// The <see cref="ClusterMethodTypeResult"/>.
        /// </returns>
        public ClusterMethodTypeResult QueryAllClusterMethodTypes(ClusterMethodTypeQuery clusterMethodTypeQuery)
        {
            var result = new ClusterMethodTypeResult();

            var list = this.Session.QueryOver<ClusterMethodType>().List().OrderBy(x => x.Name);
            
            result.TotalRowCount = list.Count();
            
            foreach (ClusterMethodType type in list)
            {
                result.List.Add(Services.Dto.ClusterMethodType.Convert(type));
            }

            return result;
        }

        #endregion

        #region Methods

        /// <summary>
        /// The delete cluster method.
        /// </summary>
        /// <param name="cmd">
        /// The cmd.
        /// </param>
        internal void DeleteClusterMethod(DeleteClusterMethodCommand cmd)
        {
            if (cmd.Dto != null)
            {
                var method = this.Session.Get<ClusterMethod>(cmd.Dto);
                if (method != null)
                {
                    foreach (File file in method.Files)
                    {
                        this.Session.Delete(file);
                    }

                    this.Session.Delete(method);
                }
            }
        }

        /// <summary>
        /// The update cluster method.
        /// </summary>
        /// <param name="cmd">
        /// The cmd.
        /// </param>
        internal void UpdateClusterMethod(UpdateClusterMethodCommand cmd)
        {
            if (cmd.Dto != null)
            {
                var method = this.Session.Get<ClusterMethod>(cmd.Dto.ID);
                if (method != null)
                {
                    method.Comments = cmd.Dto.Comments;
                    method.ArchiveLocation = cmd.Dto.ArchiveLocation;
                    method.Type = this.Session.Get<ClusterMethodType>(cmd.Dto.Type);

                    if (cmd.Dto.Files != null && cmd.Dto.Files.Any())
                    {
                        IEnumerable<Guid> fileIDs = cmd.Dto.Files;

                        foreach (Guid id in fileIDs)
                        {
                            var newAddition = this.Session.Get<File>(id);
                            if (newAddition != null && !method.Files.Contains(newAddition))
                            {
                                method.Files.Add(newAddition);
                            }
                        }
                    }

                    this.Session.Update(method);
                }
            }
        }

        #endregion

        internal void DeleteClusterMethodFile(DeleteClusterMethodFileCommand cmd)
        {
            if (cmd.OwnerClusterMethodID.HasValue && cmd.OwnerClusterMethodID.Value != Guid.Empty)
            {
                if (cmd.ClusterMethodFileID.HasValue && cmd.ClusterMethodFileID.Value != Guid.Empty)
                {
                    var clusterMethod = this.Session.Get<ClusterMethod>(cmd.OwnerClusterMethodID);
                    if (clusterMethod != null)
                    {
                        var fileToDelete = this.Session.Get<File>(cmd.ClusterMethodFileID);

                        if(fileToDelete != null){
                            clusterMethod.Files.Remove(fileToDelete);
                            this.Session.Update(clusterMethod);

                            FileActioner fActioner = new FileActioner(this.Session, this.ActiveUser);
                            fActioner.DeleteFile(cmd.ClusterMethodFileID.Value);
                        }
                    }
                }
            }
        }
    }
}